// Gtk+ File chooser button
// Copyright 2006 (C) Ralph Thomas

#include <view/file_button.h>
#include <gtk/os_utilities.hpp>
#include <binder.hpp>

namespace view {
	class file_button_t {
		typedef adobe::implementation::signal_wrapper_zero_t<void> selection_change_t;
		adobe::auto_ptr<GtkWidget>	control_m;
		selection_change_t		selection_change_m;
		adobe::binder_helper_t		binder_m;

		void selection_change() {
			char* path = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER( control_m.get() ) );
			if( !path ) return;
			binder_m.set( adobe::value_t( std::string( path ) ) );
			g_free( path );
		}
		void binder_changed( const adobe::value_t& new_val ) {
			std::string path;
			if( !new_val.get( path ) ) return;
			gtk_file_chooser_set_filename( GTK_FILE_CHOOSER( control_m.get() ), path.c_str() );
		}
	  public:
		file_button_t( bool directory, const adobe::value_t& bind, adobe::sheet_t& sheet )
		: binder_m( sheet ) {
			//
			// Make the button widget. This is a single widget in
			// Gtk+.
			//
			control_m.reset( gtk_file_chooser_button_new( "",
				directory ?
				GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER :
				GTK_FILE_CHOOSER_ACTION_OPEN ) );
			selection_change_m.set_callback( boost::bind( &file_button_t::selection_change, this ) );
			selection_change_m.connect( control_m.get(), "selection-changed" );
			//
			// Connect to our binder.
			//
			binder_m.initialize( bind, boost::bind( &file_button_t::binder_changed, this, _1 ),
				boost::bind( &gtk_widget_set_sensitive, control_m.get(), _1 ) );
		}
		GtkWidget* getWidget() const { return control_m.get(); }
	};
	adobe::widget_node_t file_button_factory(
		const adobe::dictionary_t&	parameters,
		const adobe::widget_node_t&	parent,
		const adobe::factory_token_t&	token,
		bool				directory )
	{
		//
		// Must be bound to a path value.
		//
		adobe::value_t bind = parameters.at( adobe::static_name_t( "bind" ) );
		//
		// Create the button.
		//
		file_button_t* button = new file_button_t( directory, bind, token.sheet_m );
		token.assemblage_m.delete_on_destruction( button );
		//
		// Insert it into the display.
		// 
		GtkWidget* w = button->getWidget();
		adobe::display_t::position_t display_token( adobe::insert( adobe::get_main_display(), parent.display_token_m, w ) );
		adobe::display_t::position_t overlay_token( token.overlay_m.insert( parent.overlay_token_m ) );
		//
		// Bind it into Eve.
		//
		adobe::eve_t::signal_suite_t	signals;
		eve_client::place_func_t	placer;
		placer = boost::bind( &adobe::implementation::set_bounds_widget, w, _1, _2 );
		signals.eve_calculate_proc_m = boost::bind( &eve_client::utility_widget_calculate, adobe::implementation::best_bounds_widget( w ), _1 );
		signals.eve_place_proc_m = boost::bind( &eve_client::utility_widget_place, placer, _1, _2, boost::ref( token.overlay_m ), overlay_token );
		//
		// Register the widget with Eve.
		//
		adobe::eve_t::iterator eve_token(
			token.layout_m.add_view_element( parent.eve_token_m,
				adobe::eve_t::insert_element_t(
					adobe::eve_t::calculate_data_t(),
					false,
					parameters,
					signals )
				)
			);
		//
		// Return the new button.
		//
		return adobe::widget_node_t( parent.size_m, eve_token, display_token, overlay_token );
	}
}
